var Configure   =   require("../util/config-parser");
var ServerProtocol  = require("../rpc-json/json-server");
var BindAdapter     = require("./bindAdapter");
var Endpoint        = require("../util/endpoint");

var HeroServer  = function() {
    this._adapters   =   [];
    this._servants  =   {};
    this._configure =   undefined;
    this._configureFile =   "";
    this.Application    =   "";
    this.ServerName     =   "";
}

module.exports  =   HeroServer;

HeroServer.BindAdapterOption    = function() {
    this.endpoint   =   "";
    this.name       =   "";
    this.servant    =   "";
    this.maxconns   =   1024;
    this.prototocolName =   "json";
    this.protocol   =   undefined;
    this.handleImp  =   undefined;
}

HeroServer.prototype.__defineGetter__("communicator", function() { return this._communicator; })
HeroServer.prototype.__defineGetter__("configure", function() { return this._configure; })

HeroServer.prototype.initialize = function(sConfigFile, initFunction) {
    this._configureFile =   sConfigFile;
    this._configure     =   new Configure();
    this._configure.parseFile(this._configureFile);
    this._initializeServer();

    initFunction && initFunction(this);
}

HeroServer.prototype.addServant =   function(ServantHandle, ServantName) {
    this._servants[ServantName] =   ServantHandle;
}

HeroServer.prototype.start  =   function(option) {
    option && this._addBindAdapter(option);
    return this._waitForShutdown();
}

HeroServer.prototype.stop   =   function() {
    for(var i = 0; i < this._adapters.length; i++ ) {
        this._adapters[i].stop();
    }
    this._adapters.slice(0, this._adapters.length);
}

HeroServer.prototype._initializeServer  =   function() {
    this.Application    =   this._configure.get("application.server.app");
    this.ServerName     =   this._configure.get("application.server.server");

    var svrList =   this._configure.getDomain("application.server");
    for(var i = 0; i < svrList.length; i++) {
        var config =    this._configure.get("application.server.<" + svrList[i] + ">");
        var option  =   new HeroServer.BindAdapterOption();
        option.name =   svrList[i];
        option.servant  =   config.servant;
        option.endpoint =   config.endpoint;
        option.maxconns =   config.maxconns;
        option.prototocolName   =   config.protocol;
        option.protocol =   ServerProtocol;

        this._addBindAdapter(option);
    }
}

HeroServer.prototype._addBindAdapter    =   function(option) {
    var adapter =   new BindAdapter();
    adapter.name    =   option.name;
    adapter.servantName =   option.servant;
    adapter.endpoint    =   Endpoint.parse(option.endpoint);
    adapter.maxconns    =   option.maxconns ? option.maxconns : 1024;
    adapter.prototocolName  =   option.prototocolName;
    adapter.protocol    =   option.protocol;

    this._servants[adapter.servantName] =   option.handleImp;
    this._adapters.push(adapter);
}

HeroServer.prototype._waitForShutdown   =   function() {
    var initializePromiseArray  =   [];
    for(var i = 0; i < this._adapters.length; i++)
    {
        (function() {
            var adapter =   this._adapters[i];
            adapter.handleImp   =   new this._servants[adapter.servantName]();
            var promise =   adapter.handleImp.initialize();
            if(promise && typeof promise.then == "function") {
                initializePromiseArray.push(promise.then(function(data) {
                    adapter.start();
                    return data;
                }));
            } else {
                adapter.start();
            }
        }).call(this);
    }
    if(initializePromiseArray.length > 0 ) {
        return promise.all(initializePromiseArray);
    }
}

var SimpleServer    =   function(HandleImp) {
    this._server    =   new HeroServer();
    this._handleImp =   HandleImp;
}

SimpleServer.prototype.start    =   function(option) {
    var bindAdapterOption   =   new HeroServer.BindAdapterOption();
    bindAdapterOption.endpoint  =   option.endpoint;
    bindAdapterOption.servant   =   option.servant;
    bindAdapterOption.maxconns  =   option.maxconns;
    bindAdapterOption.prototocolName    =   option.protocol;
    bindAdapterOption.handleImp         =   option.handleImp ? option.handleImp : this._handleImp;

    return this._server.start(bindAdapterOption);
}

SimpleServer.prototype.stop =   function() {
    this._server && this._server.stop();
}

HeroServer.createServer =   function(HandleImp) {
    return HandleImp ? new SimpleServer(HandleImp) : new HeroServer();
}

HeroServer.getServant   =   function(sConfigFile, ServantName) {
    var configure   =   new Configure();
    configure.parseFile(sConfigFile);

    var svrList = configure.getDomain("application.server");
    var servants = [];
    for(var i = 0; i < svrList.length; i++) {
        var config = configure.get("application.server.<" + svrList[i] + ">");
        if(ServantName && config.servant === ServantName) {
            servants.push(config);
            break;
        }

        if(ServantName === undefined) {
            servants.push(config);
        }
    }

    return servants;
}